package httpsproxy

import (
	"log"
	"net"
	"net-server/encrypt"
	"strings"
	"time"
)

var LocalIP = "45.195.201.223:8000"

func Start(port string) {
	serve := newServe(port)
	serve.listen()
}

func newServe(port string) *serve {
	return &serve{port: port}
}

type serve struct {
	port string
}

func (s *serve) listen() {
	listen, err := net.Listen("tcp", s.port)
	if err != nil {
		log.Fatal(err)
	}

	for {
		conn, err := listen.Accept()
		if err != nil {
			log.Println(err)
			continue
		}
		c := &connEngine{cConn: conn}
		go c.establish()
	}
}

type connEngine struct {
	cConn   net.Conn
	addr    string
	method  string
	message string
	sConn   net.Conn
}

func (e *connEngine) establish() {
	start := time.Now().UnixNano() / 1e6
	e.parseUrl()
	e.establishConnect()
	end := time.Now().UnixNano() / 1e6
	log.Println("建立 耗时", end-start)
	t := &tranfer{cConn: e.cConn, sConn: e.sConn}
	t.transfer()
}

func (e *connEngine) parseUrl() {
	buffer := make([]byte, 1024)
	n, err := e.cConn.Read(buffer)
	if err != nil {
		log.Println("read err ", err)
		return
	}
	crypt, _ := encrypt.AesDeCrypt(buffer[0:n], encrypt.PrivateKey)
	var lines = string(crypt)
	log.Println(lines)
	e.message = lines
	addr, method := e.parseHTTPHead(lines)
	if addr == LocalIP {
		return
	}
	e.addr = addr
	e.method = method
}

func (e *connEngine) parseHTTPHead(lines string) (addr, method string) {
	linesArr := strings.Split(lines, "\r\n")
	head := make(map[string]string, 10)
	for i, s := range linesArr {
		if i == 0 {
			continue
		}
		if s == "" {
			continue
		}
		lineArr := strings.Split(s, ": ")
		if len(lineArr) != 2 {
			continue
		}
		head[lineArr[0]] = lineArr[1]
	}
	firstLine := linesArr[0]
	firstLineArr := strings.Split(firstLine, " ")
	method = firstLineArr[0]
	addr = head["Host"]
	if !strings.Contains(addr, ":") {
		if method == "CONNECT" {
			addr += ":443"
		} else {
			addr += ":80"
		}
	}
	return addr, method
}

func (e *connEngine) establishConnect() {
	if e.addr == "" {
		return
	}
	//log.Println("begin to connect: ", e.addr)
	sConn, err := net.Dial("tcp", e.addr)
	if err != nil {
		log.Println("连接建立失败：", err)
		e.cConn.Close()
		return
	}
	//log.Println("connect success: ", e.addr)
	e.sConn = sConn
	resp := "HTTP/1.1 200 Connection Established\n\n"
	aesEncrypt, err := encrypt.AesEncrypt([]byte(resp), encrypt.PrivateKey)
	if err != nil {
		return
	}
	e.cConn.Write(aesEncrypt)
	if e.method == "GET" {
		sConn.Write([]byte(e.message))
	}
}
